Laboratorio 004: EDA de Imágenes de Tórax + Convolución (Efecto del Ancla

Ingeniería Biomédica

PSIM
Autor/a

Ph.D. Pablo Eduardo Caicedo Rodríguez

Fecha de publicación

16 de octubre de 2025

Servicio de Radiología – Auditoría de calidad en la ronda de la mañana

Como ingeniero(a) biomédico(a) del Servicio de Radiología, cada mañana debes auditar la calidad de radiografías de tórax antes de liberar agenda clínica. Trabajarás con un subconjunto balanceado del dataset Chest X-Ray Images (Pneumonia) (clases: NORMAL y PNEUMONIA). Cita la fuente y fecha de descarga en tu primera diapositiva.


Reglas de la práctica

  • Solo OpenCV (cv2); se permite NumPy como soporte de arreglos.
  • La evaluación es por presentación (no por informe escrito).
  • Debes usar explícitamente las funciones: cv.calcHist, cv.compareHist, cv.filter2D con anchor, y cv.Laplacian para enfoque.
  • Muestra seudocódigo y resultados (figuras/tablas) en las diapositivas. Evita código ejecutable en la presentación.
  • Todas las funciones deben ser comprendidas desde el punto de vista matemático y computacional.

Objetivos de aprendizaje

  1. Ejecutar un EDA por clase (NORMAL vs PNEUMONIA) con estadísticas descriptivas e histogramas.
  2. Comparar histogramas globales y por ROIs, justificando la métrica más informativa.
  3. Estimar calidad (enfoque por Laplaciano; contraste) con operadores de OpenCV.
  4. Demostrar el efecto del píxel de anclaje (anchor) en una convolución 2D y discutir su impacto en mapas de bordes/mediciones.

Datos (obligatorio)

  • Fuente: Kaggle – Chest X-Ray Images (Pneumonia) https://www.kaggle.com/datasets/paultimothymooney/chest-xray-pneumonia
  • Clases: NORMAL y PNEUMONIA.
  • Muestreo sugerido: 60 imágenes por clase (balanceado) para auditoría (no entrenamiento).
  • Buenas prácticas: Trabaja sobre copias; no modifiques originales. Documenta toda normalización/realce en una bitácora.

Slide 1 (requisito): Equipo y roles, fuente del dataset, fecha de descarga, estructura de carpetas y riesgos de sesgo (edad, equipo Rx, proyección, etc.).


Entregable y logística de evaluación

  • Presentación por equipos: 6–8 minutos + 2 minutos de preguntas. Máximo 8 diapositivas.
  • Secuencia sugerida de slides:
    1. Portada y datos.
    2. Muestreo y control de sesgos.
    3. EDA global (estadísticos + histogramas por clase).
    4. Comparación de histogramas (global y ROIs).
    5. Calidad (enfoque, contraste) con lectura clínica.
    6. Convolución + ancla (delta + ROI real).
    7. Recomendaciones de QA y límites.
    8. Apéndice: funciones usadas e hiperparámetros.

Rúbrica de evaluación (100 pts)

Criterio Descripción Evidencia esperada en la presentación Puntos
Contexto clínico y datos Cita del dataset (Kaggle), clases, balance, riesgos de sesgo, trazabilidad. Slides 1–2 bien documentadas. 10
EDA descriptivo Estadísticos (min, max, media, mediana, p5/p95, std, IQR/MAD) por clase; histogramas claros. Uso obligatorio: cv.calcHist. Slide 3 (tablas/figuras) + interpretación breve. 20
Comparación de histogramas Uso obligatorio: cv.compareHist con ≥2 métricas (p. ej., Correlación, Chi-cuadrado, Intersección, Bhattacharyya); global y en ROIs comparables. Slide 4 con tabla de métricas y conclusión justificada. 20
Calidad (enfoque/contraste) Enfoque por varianza del Laplaciano (cv.Laplacian) y al menos una medida de contraste (p. ej., Michelson o std/mean). Slide 5 con resultados y lectura clínica. 20
Convolución y ancla Uso obligatorio: cv.filter2D con anchor variado. Demostración con imagen delta y ROI real; explicación del desplazamiento espacial e impacto en mediciones. Slide 6 con figuras claras + explicación. 25
Recomendaciones y límites Acciones de QA (umbrales/alertas), riesgos del posprocesado (p. ej., CLAHE), límites y próximos pasos. Slide 7–8 con lista accionable. 5

Aprobación mínima: 60 pts. Penaliza exceder tiempo, no citar dataset o no usar las funciones requeridas.


Guía técnica

Funciones OpenCV a utilizar (obligatorias): cv.calcHist (histogramas), cv.compareHist (comparación), cv.filter2D + anchor (convolución), cv.Laplacian (enfoque).

1) EDA por clase (NORMAL vs PNEUMONIA)

Tareas: - Calcular, por clase, min, max, media, mediana, p5/p95, std, IQR/MAD. - Generar histogramas (bins=256, rango 0–255) y visualizarlos de forma comparable.

Seudocódigo:

for CLASS in [NORMAL, PNEUMONIA]:
    IMGS = read_all_grayscale(CLASS)              // cv.imread(..., cv.IMREAD_GRAYSCALE)
    IMGS_8U = normalize_to_8bit(IMGS)             // asegurar 0–255
    STATS[CLASS] = descriptive_stats(IMGS_8U)     // min, max, mean, median, p5/p95, std, IQR/MAD
    H_CLASS = mean_histogram(IMGS_8U)             // cv.calcHist por imagen y promedio
plot_overlaid(H_NORMAL, H_PNEUMONIA)              // comparar curvas en un mismo eje

Pregunta con context: En la ronda de Urgencias, se reportan placas con posible bajo rango dinámico. A partir de tus histogramas y percentiles p5/p95, ¿hay evidencia de saturación o subexposición en alguna clase? ¿Qué implicaría para la lectura del radiólogo de guardia?


2) Comparación de histogramas (global y por ROI)

Tareas: - Comparar histogramas globales y de ROIs equivalentes entre clases. - Usar al menos dos métricas de cv.compareHist (p. ej., Correlación y Bhattacharyya).

Seudocódigo:

ROI_A = center_crop(select_example(NORMAL))
ROI_B = center_crop(select_example(PNEUMONIA))

H_A = normalized_histogram(ROI_A)   // cv.calcHist + normalización
H_B = normalized_histogram(ROI_B)

SCORES = {
  "CORRELATION": compareHist(H_A, H_B, METHOD_CORREL),
  "BHATTACHARYYA": compareHist(H_A, H_B, METHOD_BHATTACHARYYA)
}
render_table(SCORES)

Pregunta con contexto: En regiones hiliares la comparación muestra alta intersección entre clases. ¿Lo atribuyes a superposición anatómica o a variabilidad de exposición? ¿Qué acción de QA propones (reencuadre, repetición, anotación del técnico)?


3) Calidad: enfoque (Laplaciano) y contraste

Tareas: - Estimar enfoque con cv.Laplacian y reportar la varianza de la respuesta (FOCUS). - Reportar una medida de contraste (p. ej., Michelson = (max−min)/(max+min) o std/mean).

Seudocódigo:

ROI = center_crop(select_example(any_class))
LAP = Laplacian(ROI, ddepth=32F, ksize=3)    // cv.Laplacian
FOCUS = variance(LAP)
CONTRAST = contrast_metric(ROI)              // Michelson o std/mean

report({"FOCUS": FOCUS, "CONTRAST": CONTRAST})

Pregunta con contexto (colocar textual en la slide): En un turno nocturno con posible movimiento del paciente, ¿qué umbral de enfoque (FOCUS) propondrías para repetir la Rx minimizando dosis? ¿Cómo lo comunicarías al técnico?


4) Convolución 2D y efecto del ancla (anchor)

Tareas: - Usar cv.filter2D variando anchor y mostrar el desplazamiento de la respuesta.

Diseño experimental mínimo (dos partes):

A) Imagen “delta” (7×7, con un 1 en (3,3))

DELTA = zeros(7,7); DELTA[3,3] = 1
K = ones(3,3) / 9

for ANCHOR in [(-1,-1), (0,0), (2,1)]:
    OUT = filter2D(DELTA, ddepth=-1, kernel=K, anchor=ANCHOR, borderType=BORDER_CONSTANT)
    visualize_matrix(OUT, title="anchor="+str(ANCHOR))

B) ROI real (Rx) + Laplaciano (realce de bordes)

ROI = center_crop(select_example(NORMAL))
LAP_K = [[0,-1,0],[-1,4,-1],[0,-1,0]]

for ANCHOR in [(-1,-1), (0,0), (2,2)]:
    EDGES = filter2D(ROI, ddepth=32F, kernel=LAP_K, anchor=ANCHOR, borderType=BORDER_REFLECT_101)
    show_abs(EDGES, same_scale=True)

Conclusión esperada: El ancla selecciona qué píxel de la ventana se alinea con la coordenada de salida. Cambiarla no altera la combinación lineal local, pero la ubicación de la respuesta (desfase espacial). En QA, un ancla errónea puede desalinear bordes/mediciones (p. ej., diámetro cardiotorácico) o desplazar mapas de atención.

Pregunta con contexto: Si tu pipeline de detección de bordes costales usa un ancla mal configurada y desplaza bordes ~1–2 px, ¿cómo afectaría el cálculo del diámetro cardiotorácico o la detección de consolidaciones en seguimiento? Propón una verificación de QA automatizada.


Checklist previo a la presentación


Referencias (para consulta del equipo)

  • Dataset: Kaggle – Chest X-Ray Images (Pneumonia) https://www.kaggle.com/datasets/paultimothymooney/chest-xray-pneumonia
  • OpenCV – Histogramas: cv.calcHist (documentación oficial)
  • OpenCV – Comparación de histogramas: cv.compareHist (documentación oficial)
  • OpenCV – Convolución: cv.filter2D y parámetro anchor (documentación oficial)
  • OpenCV – Operador Laplaciano: cv.Laplacian (documentación oficial)